﻿import typing
import multiprocessing
import multiprocessing.managers
import multiprocessing.synchronize
import requestNovelsLib
import datetime
import traceback
import lxml
import lxml.etree
import requests

timeFmt = "%m-%d"

__runMain = False


def getNovelHome(response: requests.Response) -> typing.Union[dict[str, list[str]], None]:
	"""
	首页查找到类型与 url 的映射
	:param response: get请求之后而的响应体
	:return: 类型名称与之匹配的 url 映射
	"""
	xpath = requestNovelsLib.XpathHtml(response.text)
	## 获取 li 节点
	liNodes = xpath.xpath(r'//div[@class="nav"]/ul/li/a')
	if xpath.resultLen() == 0:
		return
	## 类型名过滤器
	getTypeName = requestNovelsLib.getNovelTypeName()
	
	## 返回
	result: dict[str, list[str]] = {}
	## 遍历需要的类型名称
	typeNameUrl = ""
	for liNode in liNodes:
		liNodeXpathInfo = requestNovelsLib.XpathInfo(liNode)
		aTests = liNodeXpathInfo.xpath(r'./text()')
		if liNodeXpathInfo.resultLen() == 0:
			continue
		typeName = aTests[0]
		typeName = requestNovelsLib.strRemoveSpaces(typeName)
		for item in getTypeName:
			if item == typeName:
				xpathList = liNodeXpathInfo.xpath(r'./@href')
				if len(xpathList) == 0:
					break
				href = xpathList[0]
				href = href.replace(response.url, "")[1:]
				typeNameUrl = requestNovelsLib.getResponseAtStr(response, href)
				break
		if len(typeNameUrl) != 0:
			if result.get(typeName) is None:
				result[typeName] = [typeNameUrl]
			else:
				result[typeName].append(typeNameUrl)
			typeNameUrl = ""
	return result


def getPageListNovel(response: requests.Response, getCount: int, novelTypeName: str, novelTypeUrl: str, novelRootUrl: str) -> typing.Union[list[requestNovelsLib.NovelInfo], None]:
	"""
	获取小说信息
	若为 none 或 数量 0， 则退出这次类型的扫描
	:param response: get 之后的响应体
	:param getCount: 已经库存的数量
	:param novelTypeName: 小说类型名称
	:param novelTypeUrl: 小说类型 url
	:param novelRootUrl: 小说网站
	:return: 小说列表
	"""
	xpath = requestNovelsLib.XpathHtml(response.text)
	liNodes = xpath.xpath(r'//div[@class="l"]/ul/li')
	if xpath.resultLen() == 0:
		return None
	## 小说网址
	novelUrl: str = ""
	## 小说名称
	novelName: str = ""
	## 小说作者
	author: str = ""
	## 最后更新日期
	updateTime: str = ""
	## 最后更新选项
	lastItem: str = ""
	## 小说详情
	info: str = ""
	## 返回值
	result: list[requestNovelsLib.NovelInfo] = []
	# pc 转 移动
	# novelRootUrl = novelRootUrl.replace("https://www.", "https://m.", 1)
	for liNode in liNodes:
		novelUrl = novelName = novelName = author = updateTime = lastItem = info = ""
		try:
			## 获取时间
			nodeXpathInfo = requestNovelsLib.XpathInfo(liNode)
			nodeTextArray = nodeXpathInfo.xpath(r'./span[@class="s5"]/text()')
			resultLen = nodeXpathInfo.resultLen()
			if resultLen == 0:
				print(f"错误的 => 日期 [{novelTypeName} ({getCount})] error : error ==== >")
				continue
			updateTime = nodeTextArray[0]
			updateTime = updateTime.strip()
			## 时间跳出
			## 2022-09-22 11:42:11
			if not requestNovelsLib.checkUpDate(updateTime, timeFmt):
				continue
			
			## 获取名称
			nodeTextArray = nodeXpathInfo.xpath(r'./span[@class="s2"]/a/text()')
			if nodeXpathInfo.resultLen() == 0:
				print(f"错误的 => 名称 [{novelTypeName} ({getCount})] error : error ==== >")
				continue
			novelName = nodeTextArray[0]
			
			novelName = novelName.strip()
			## 获取链接
			nodeTextArray = nodeXpathInfo.xpath(r'./span[@class="s2"]/a/@href')
			if nodeXpathInfo.resultLen() == 0:
				print(f"错误的 => 链接 [{novelTypeName} ({getCount})] {novelName} :  error ==== >")
				continue
			nodeText = nodeTextArray[0]
			if nodeText is None or len(nodeText) == 0:
				continue
			novelUrl = f"http://{novelRootUrl}/{nodeText[1:]}"
			novelUrl = novelUrl.strip()
			## 获取最后更新项
			nodeTextArray = nodeXpathInfo.xpath(r'./span[@class="s3"]/a/text()')
			if nodeXpathInfo.resultLen() == 0:
				continue
			lastItem = nodeTextArray[0]
			lastItem = lastItem.strip()
			## 获取作者
			nodeTextArray = nodeXpathInfo.xpath(r'./span[@class="s4"]/a/text()')
			if nodeXpathInfo.resultLen() != 0:
				author = nodeTextArray[0]
				author = author.strip()
			else:
				print(f"错误的 => 作者 [{novelTypeName} ({getCount})] {novelName} : {novelUrl} ==== >")
			
			## 获取详情
			# nodeTextArray = nodeXpathInfo.xpath(r'./dd[@class="book_des"]/text()')
			# if nodeXpathInfo.resultLen() != 0:
			# 	xpathArray = nodeTextArray[0]
			# 	if xpathArray is not None and len(xpathArray) > 0:
			# 		info = xpathArray
			# else:
			# 	print(f"错误的 => 详情 [{novelTypeName} ({getCount})] {novelName} : {novelUrl} ==== >")
			#
			getCount += 1
			print(f"发现 [{novelTypeName} ({getCount})] {novelName} : {novelUrl} ==== >")
			
			## 添加单个对象
			result.append(requestNovelsLib.NovelInfo(novelRootUrl=novelRootUrl, novelTypeName=novelTypeName, novelTypeUrl=novelTypeUrl, novelUrl=novelUrl, novelName=novelName, author=author, updateTime=updateTime, lastItem=lastItem, info=info, updateTimeFmt=timeFmt))
		except:
			traceback.print_exc()
	return result


def getPageNextUrl(response: requests.Response, exsiNovel: int, noveList, appenLen, novelTypeName: str, novelTypeUrl: str, novelRootUrl: str) -> typing.Union[str, None]:
	"""
	获取小说翻页的下一页
	:param response: get 之后的响应体
	:param exsiNovel: 已经库存的小说
	:param noveList: 查找到的小说
	:param appenLen: 新增数量
	:param novelTypeName: 小说类型名称
	:param novelTypeUrl: 小说类型 url
	:param novelRootUrl: 小说网站
	:return: 下一页，不存在则返回 none
	"""
	if noveList is None or len(noveList) == 0:
		return None
	if appenLen == 0:
		return None
	try:
		xpath = requestNovelsLib.XpathHtml(response.text)
		pageList = xpath.xpath(r'//div[@class="pages"]/a/@href')
		if xpath.resultLen() == 0:
			return None
		nextLastNoede = pageList[-1]
		resultNextPageUrl = f"http://{novelRootUrl}/{nextLastNoede[1:]}"
		return resultNextPageUrl
	except BaseException as es:
		traceback.print_exc()
	return None


def sort(novel: requestNovelsLib.NovelInfo):
	return novel.updateTime


__runTime = None


def setRunTime(time):
	global __runTime
	__runTime = time


def getRunTime():
	global __runTime
	return __runTime


def getRootUrl():
	return 'www.x81zw.io'


def modeRequestGetUrl(lock: multiprocessing.synchronize.Lock = None,workerThreadNumber=0, nextRequestTimeSece=2, titleSleepTime=10):
	global __runMain
	if not __runMain:
		if lock is None:
			raise RuntimeError("请在调用时候设置它的进程锁")
	else:
		if lock is None:
			lock = multiprocessing.Lock()
	
	rootUrl = getRootUrl()
	requestUrl = requestNovelsLib.ResponseNovel(f'http://{rootUrl}/')
	newFolder = requestNovelsLib.getUrlTargetFolder(rootUrl)
	try:
		## 获取类型类型的请求页面
		runEndTime = requestNovelsLib.ayscRequestGetUrl(requestUrl, getNovelHome, getPageListNovel, getPageNextUrl, rootUrl, newFolder, __runMain, proLock=lock, nextRequestTimeSece=nextRequestTimeSece, workerThreadNumber=workerThreadNumber, titleSleepTime=titleSleepTime)
		setRunTime(runEndTime)
	except:
		traceback.print_exc()
	return


if __name__ == '__main__':
	__runMain = True
	requestNovelsLib.initLib()
	modeRequestGetUrl()
